#region Using directives
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Text;
using RacingGame.Helpers;
#endregion

namespace RacingGame.Graphics
{
    class TextureFont : IDisposable
    {
        #region Constants
        const string GameFontFilename = "GameFont.png";

        const int FontHeight = 36;

        const int SubRenderHeight = 5;

        static Rectangle[] CharRects = new Rectangle[126 - 32 + 1]
        {
            new Rectangle(0, 0, 1, 8), // space
            new Rectangle(1, 0, 11, 10),
            new Rectangle(12, 0, 14, 13),
            new Rectangle(26, 0, 20, 18),
            new Rectangle(46, 0, 20, 18),
            new Rectangle(66, 0, 24, 22),
            new Rectangle(90, 0, 25, 23),
            new Rectangle(115, 0, 8, 7),
            new Rectangle(124, 0, 10, 9),
            new Rectangle(136, 0, 10, 9),
            new Rectangle(146, 0, 20, 18),
            new Rectangle(166, 0, 20, 18),
            new Rectangle(186, 0, 10, 8),
            new Rectangle(196, 0, 10, 9),
            new Rectangle(207, 0, 10, 8),
            new Rectangle(217, 0, 18, 16),
            new Rectangle(235, 0, 20, 19),

            new Rectangle(0, 36, 20, 18), // 1
            new Rectangle(20, 36, 20, 18),
            new Rectangle(40, 36, 20, 18),
            new Rectangle(60, 36, 21, 19),
            new Rectangle(81, 36, 20, 18),
            new Rectangle(101, 36, 20, 18),
            new Rectangle(121, 36, 20, 18),
            new Rectangle(141, 36, 20, 18),
            new Rectangle(161, 36, 20, 18), // 9
            new Rectangle(181, 36, 10, 8),
            new Rectangle(191, 36, 10, 8),
            new Rectangle(201, 36, 20, 18),
            new Rectangle(221, 36, 20, 18),

            new Rectangle(0, 72, 20, 18), // >
            new Rectangle(20, 72, 19, 17),
            new Rectangle(39, 72, 26, 24),
            new Rectangle(65, 72, 22, 20),
            new Rectangle(87, 72, 22, 20),
            new Rectangle(109, 72, 22, 20),
            new Rectangle(131, 72, 23, 21),
            new Rectangle(154, 72, 20, 18),
            new Rectangle(174, 72, 19, 17),
            new Rectangle(193, 72, 23, 21),
            new Rectangle(216, 72, 23, 21),
            new Rectangle(239, 72, 11, 10),

            new Rectangle(0, 108, 15, 13), // J
            new Rectangle(15, 108, 22, 20),
            new Rectangle(37, 108, 19, 17),
            new Rectangle(56, 108, 29, 26),
            new Rectangle(85, 108, 23, 21),
            new Rectangle(108, 108, 24, 22), // O
            new Rectangle(132, 108, 22, 20),
            new Rectangle(154, 108, 24, 22),
            new Rectangle(178, 108, 24, 22),
            new Rectangle(202, 108, 21, 19),
            new Rectangle(223, 108, 17, 15), // T

            new Rectangle(0, 144, 22, 20), // U
            new Rectangle(22, 144, 22, 20),
            new Rectangle(44, 144, 30, 28),
            new Rectangle(74, 144, 22, 20),
            new Rectangle(96, 144, 20, 18),
            new Rectangle(116, 144, 20, 18),
            new Rectangle(136, 144, 10, 9),
            new Rectangle(146, 144, 18, 16),
            new Rectangle(167, 144, 10, 9),
            new Rectangle(177, 144, 17, 16),
            new Rectangle(194, 144, 17, 16),
            new Rectangle(211, 144, 17, 16),
            new Rectangle(228, 144, 20, 18),

            new Rectangle(0, 180, 20, 18), // b
            new Rectangle(20, 180, 18, 16),
            new Rectangle(38, 180, 20, 18),
            new Rectangle(58, 180, 20, 18), // e
            new Rectangle(79, 180, 14, 12), // f
            new Rectangle(93, 180, 20, 18), // g
            new Rectangle(114, 180, 19, 18), // h
            new Rectangle(133, 180, 11, 10),
            new Rectangle(145, 180, 11, 10), // j
            new Rectangle(156, 180, 20, 18),
            new Rectangle(176, 180, 11, 9),
            new Rectangle(187, 180, 29, 27),
            new Rectangle(216, 180, 20, 18),
            new Rectangle(236, 180, 20, 19),

            new Rectangle(0, 216, 20, 18), // p
            new Rectangle(20, 216, 20, 18),
            new Rectangle(40, 216, 13, 12), // r
            new Rectangle(53, 216, 17, 16),
            new Rectangle(70, 216, 14, 11), // t
            new Rectangle(84, 216, 19, 18),
            new Rectangle(104, 216, 17, 16),
            new Rectangle(122, 216, 25, 23),
            new Rectangle(148, 216, 19, 17),
            new Rectangle(168, 216, 18, 16),
            new Rectangle(186, 216, 16, 15),
            new Rectangle(203, 216, 10, 9),
            new Rectangle(214, 216, 12, 11), // |
            new Rectangle(227, 216, 10, 9),
            new Rectangle(237, 216, 18, 17),
        };
        #endregion

        #region Variables
        Texture fontTexture;

        SpriteBatch fontSprite;
        #endregion

        #region Properties
        public static int Height
        {
            get
            {
                return BaseGame.YToRes1050(FontHeight - SubRenderHeight);
            }
        }
        #endregion

        #region Constructor
        public TextureFont()
        {
            fontTexture = new Texture(GameFontFilename);
            fontSprite = new SpriteBatch(BaseGame.Device);
        }
        #endregion

        #region Dispose
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (fontTexture != null)
                    fontTexture.Dispose();
                if (fontSprite != null)
                    fontSprite.Dispose();
            }
        }
        #endregion

        #region Get text width
        public static int GetTextWidth(string text)
        {
            int width = 0;
            char[] chars = text.ToCharArray();
            for (int num = 0; num < chars.Length; num++)
            {
                int charNum = (int)chars[num];
                if (charNum >= 32 &&
                    charNum - 32 < CharRects.Length)
                {
                    width += BaseGame.XToRes1400(CharRects[charNum - 32].Height);
                }
                return width;
            }
        }
        #endregion

        #region Write methods
        #region FontToRender helper class
        internal class FontToRender
        {
            #region Variables
            public int x, y;
            public string text;
            public Color color;
            public float scale;
            #endregion

            #region Constructor
            public FontToRender(int setX, int setY, string setText, Color setColor)
            {
                x = setX;
                y = setY;
                text = setText;
                color = setColor;
                scale = 1.0f;
            }

            public FontToRender(int setX, int setY, string setText, Color setColor,
                float setScale)
            {
                x = setX;
                y = setY;
                text = setText;
                color = setColor;
                scale = setScale;
            }
            #endregion
        }
        #endregion

        static List<FontToRender> remTexts = new List<FontToRender>();

        public static void WriteText(int x, int y, string text, Color color)
        {
            remTexts.Add(new FontToRender(x, y, text, color));
        }

        public static void WriteText(int x, int y, string text)
        {
            remTexts.Add(new FontToRender(x, y, text, Color.White);
        }

        public static void WriteTextCentered(int x, int y, string text)
        {
            WriteText(x - GetTextWidth(text) / 2, y - Height / 2, text);
        }

        public static void WriteTextCentered(int x, int y, string text,
            Color color, float scale)
        {
            int width = TextureFont.GetTextWidth(text);
            remTexts.Add(new FontToRender(
                x - (int)Math.Round(width * scale / 2),
                y - (int)Math.Round(TextureFont.Height * scale / 2),
                text, color, scale));
        }

        public static void WriteGameTime(int x, int y, int timeMilliseconds,
            Color col)
        {
            WriteText(x, y,
                (timeMilliseconds < 0 ? "-" : "") + 
                ((Math.Abs(timeMilliseconds) / 1000) / 60) + ":" + 
                ((Math.Abs(timeMilliseconds) / 1000) % 60).ToString("00") + "." +
                ((Math.Abs(timeMilliseconds) / 10) % 100).ToString("00"), 
                col);
        }
        #endregion

        #region Write all
        public void WriteAll()
        {
            if (remTexts.Count == 0)
                return;

            fontSprite.Begin(SpriteBlendMode.AlphaBlend);
            for (int textNum = 0; textNum < remTexts.Count; textNum++)
            {
                FontToRender fontText = remTexts[textNum];

                int x = fontText.x;
                int y = fontText.y;
                Color color = fontText.color;
                char[] chars = fontText.text.ToCharArray();
                for (int num = 0; num < chars.Length; num++)
                {
                    int charNum = (int)chars[num];
                    if (charNum >= 32 &&
                            charNum - 32 < CharRects.Length)
                    {
                        Rectangle rect = CharRects[charNum - 32];
                        rect.Y += 1;
                        rect.Height = FontHeight;
                        Rectangle destRect = new Rectangle(x,
                            y - BaseGame.YToRes1050(SubRenderHeight),
                            rect.Width, rect.Height);

                        destRect.Width = BaseGame.XToRes1400(
                            (int)Math.Round(destRect.Width * fontText.scale));
                        destRect.Height = BaseGame.YToRes1050(
                            (int)Math.Round(destRect.Height * fontText.scale));

                        fontSprite.Draw(fontTexture.XnaTexture, destRect, rect, color);

                        int charWidth = CharRects[charNum - 32].Height;
                        x += BaseGame.XToRes1400(
                            (int)Math.Round(charWidth * fontText.scale));
                    }
                }
            }

            fontSprite.End();
            remTexts.Clear();
        }
        #endregion
    }
}
